﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyLibrary.API.Ext
{
	/// <summary>
	/// Container and definition class for Ext TreePanel Node items. Use an instance of this class as Root item 
	/// and add all children that should become 1st-level TreePanel items.
	/// </summary>
	public class MenuItem
	{
		private string MenuID(int Level, int Index)
		{
			return string.Format("{0}{1}", Level, Index);
		}
		private string _text = "";
		public string Text
		{
			get
			{
				if (string.IsNullOrEmpty(_text))
				{
					return "BLANK";
				}
				else
				{
					return _text;
				}
			}
			set 
			{
				_text = value;
			}
		}
		public bool IsParent { get; set; }
		private bool IsLeaf()
		{
			return !IsParent;
		}
		public LoadTab ClickCommand { get; set; }
		public List<MenuItem> Children;
        private string iconCls { get; set; }

		/// <summary>
		/// Instantiates new menu item.
		/// </summary>
		public MenuItem()
		{
			this.Text = "";
			this.IsParent = false;
			this.ClickCommand = null;
			this.Children = null;
            this.iconCls = string.Empty;
		}

		/// <summary>
		/// Instantiates new menu item.
		/// </summary>
		/// <param name="text">Display name of menu item.</param>
		public MenuItem(string text)
		{
			this.Text = text;
			this.IsParent = false;
			this.ClickCommand = null;
			this.Children = null;
            this.iconCls = string.Empty;
		}

        /// <summary>
        /// Instantiates new menu item.
        /// </summary>
        /// <param name="text">Display name of menu item.</param>
        public MenuItem(string text, string iconCls)
        {
            this.Text = text;
            this.IsParent = false;
            this.ClickCommand = null;
            this.Children = null;
            this.iconCls = iconCls;
        }

		/// <summary>
		/// Instantiates new menu item as a parent/group-container.
		/// </summary>
		/// <param name="text">Display name of menu item.</param>
		/// <param name="isparent">Current item is a parent/group-container.</param>
		public MenuItem(string text, bool isparent)
		{
			this.Text = text;
			this.IsParent = isparent;
			this.ClickCommand = null;
			this.Children = null;
            this.iconCls = string.Empty;
		}

		/// <summary>
		/// Instantiates new menu item that includes a click-function.
		/// Note: Parents may not contain click-functions, so it is assumed this item is a child menu item.
		/// </summary>
		/// <param name="text">Display name of menu item.</param>
		/// <param name="clickcmd">LoadTab object containing detail on loading a new Ext.Tab in the TabPanel this menu item's TreePanel is used with.</param>
		public MenuItem(string text, LoadTab clickcmd)
		{
			this.Text = text;
			this.IsParent = false;
			this.ClickCommand = null;
			if (clickcmd != null)
			{
				this.ClickCommand = clickcmd;
			}
			this.Children = null;
            this.iconCls = string.Empty;
		}

        public MenuItem(string text, string iconCls, LoadTab clickcmd)
        {
            this.Text = text;
            this.IsParent = false;
            this.ClickCommand = null;
            if (clickcmd != null)
            {
                this.ClickCommand = clickcmd;
            }
            this.Children = null;
            this.iconCls = iconCls;
        }

		/// <summary>
		/// Add a new child/sub-menu item to this menu item.
		/// </summary>
		/// <param name="ItemText">Display name of menu item.</param>
		/// <returns>Index of child added.</returns>
		public int AddChild(string ItemText)
		{
			return this.AddChild(new MenuItem(ItemText));
		}

        /// <summary>
        /// Add a new child/sub-menu item to this menu item.
        /// </summary>
        /// <param name="ItemText">Display name of menu item.</param>
        /// <returns>Index of child added.</returns>
        public int AddChild(string ItemText, string iconCls)
        {
            return this.AddChild(new MenuItem(ItemText, iconCls));
        }

		/// <summary>
		/// Add a new child/sub-menu item to this menu item that includes a click-function.
		/// Note: Parents may not contain click-functions, so it is assumed this item added is a child menu item.
		/// </summary>
		/// <param name="ItemText"></param>
		/// <param name="newtabid">New Tab's Client-side ID</param>
		/// <param name="frametype">Frame Config Key to use - the Key from the application's Frame Config section inside the LoadFrame function.</param>
		/// <param name="dataUrl">Source URL to call in Grid's ajax data requests.</param>
		/// <param name="cmd">Unique cmd operation parameter to send to URL.</param>
		/// <returns>Index of child added.</returns>
		public int AddChild(string ItemText, string newtabid, string frametype, string dataUrl, string cmd)
		{
			return this.AddChild(new MenuItem(ItemText, new LoadTab(newtabid, frametype, dataUrl, cmd)));
		}
        
        /// <summary>
        /// Add a new child/sub-menu item to this menu item that includes a click-function, with an additional icon cls
        /// Note: Parents may not contain click-functions, so it is assumed this item added is a child menu item.        
        /// </summary>
        /// <param name="ItemText"></param>
        /// <param name="newtabid">New Tab's Client-side ID</param>
        /// <param name="frametype">Frame Config Key to use - the Key from the application's Frame Config section inside the LoadFrame function.</param>
        /// <param name="dataUrl">Source URL to call in Grid's ajax data requests.</param>
        /// <param name="cmd">Unique cmd operation parameter to send to URL.</param>
        /// <returns>Index of child added.</returns>
        /// <param name="iconCls">The css icon representation. Ex. "icon-ok"</param>
        /// <returns>Index of child added.</returns>
        public int AddChild(string ItemText, string newtabid, string frametype, string dataUrl, string cmd, string iconCls)
        {
            return this.AddChild(new MenuItem(ItemText, iconCls, new LoadTab(newtabid, frametype, dataUrl, cmd)));
        }

		/// <summary>
		/// 
		/// </summary>
		/// <param name="ItemText"></param>
		/// <param name="newtabid"></param>
		/// <param name="jsfunction"></param>
		/// <param name="pars"></param>
		/// <returns></returns>
		public int AddChild(string ItemText, string newtabid, string jsfunction, Dictionary<string,object> pars)
		{
			return this.AddChild(new MenuItem(ItemText, new LoadTab(newtabid, jsfunction, pars)));
		}

        /// <summary>
        /// 
        /// </summary>
        /// <param name="ItemText"></param>
        /// <param name="newtabid"></param>
        /// <param name="jsfunction"></param>
        /// <param name="pars"></param>
        /// <returns></returns>
        public int AddChild(string ItemText, string iconCls, string newtabid, string jsfunction, Dictionary<string, object> pars)
        {
            return this.AddChild(new MenuItem(ItemText, iconCls, new LoadTab(newtabid, jsfunction, pars)));
        }

		/// <summary>
		/// Add a new child/sub-menu item to this menu item that includes a click-function.
		/// Note: Parents may not contain click-functions, so it is assumed this item added is a child menu item.
		/// </summary>
		/// <param name="ItemText"></param>
		/// <param name="newtabid">New Tab's Client-side ID</param>
		/// <param name="SetType">Object type indicator - which Ext object definition to use.</param>
		/// <param name="frametype">Frame Config Key to use - the Key from the application's Frame Config section inside the LoadFrame function.</param>
		/// <param name="dataUrl">Source URL to call in Grid's ajax data requests.</param>
		/// <param name="cmd">Unique cmd operation parameter to send to URL.</param>
		/// <returns>Index of child added.</returns>
		public int AddChild(string ItemText, string newtabid, ToolType SetType, string frametype, string dataUrl, string cmd)
		{
			return this.AddChild(new MenuItem(ItemText, new LoadTab(newtabid, SetType, frametype, dataUrl, cmd)));
		}

		/// <summary>
		/// Add a new child/sub-menu item to this menu item that includes a click-function.
		/// Note: Parents may not contain click-functions, so it is assumed this item added is a child menu item.
		/// </summary>
		/// <param name="ItemText">Display name of menu item.</param>
		/// <param name="clickcmd">LoadTab object containing detail on loading a new Ext.Tab in the TabPanel this menu item's TreePanel is used with.</param>
		/// <returns>Index of child added.</returns>
		public int AddChild(string ItemText, LoadTab clickcmd)
		{
			return this.AddChild(new MenuItem(ItemText, clickcmd));
		}

		/// <summary>
		/// Add a new child/sub-menu item to this menu item.
		/// Note: This disables any click-functions of the current item and makes this item function as a "group".
		/// </summary>
		/// <param name="Item">Menu item object to add as child.</param>
		/// <returns>Index of child added.</returns>
		public int AddChild(MenuItem Item)
		{
			if (this.Children == null)
			{
				this.Children = new List<MenuItem>();
				this.IsParent = true;
			}
			this.Children.Add(Item);
			return this.Children.IndexOf(Item);
		}
        

		/// <summary>
		/// Renders menu item into Ext.Node format.
		/// </summary>
		/// <param name="Level">Level of tree hierarchy that item sits at</param>
		/// <param name="MyIndex">1-based index of current item.</param>
		/// <returns>An array of formatted Ext.Nodes string.</returns>
		public string Render(int Level, int MyIndex)
		{
			string ChildItems = this.RenderChildren(Level + 1);
			if (!string.IsNullOrEmpty(ChildItems)){
				ChildItems = string.Format(", children: {0} ", ChildItems);
			}
			string UseClickCmd = "";
			if (this.ClickCommand != null)
			{
				UseClickCmd = string.Format(", config: {0} ", this.ClickCommand.Render());
			}

            string Item = "{" + string.Format(" text: \"{1}\", leaf: {2} {3} {4}", this.MenuID(Level, MyIndex), this.Text.Replace("\"", "'"), this.IsLeaf().ToString().ToLower(), ChildItems, UseClickCmd) + "}";
            if (!string.IsNullOrEmpty(this.iconCls))
            {
                Item = "{" + string.Format(" text: \"{1}\", iconCls: \"{5}\", leaf: {2} {3} {4}", this.MenuID(Level, MyIndex), this.Text.Replace("\"", "'"), this.IsLeaf().ToString().ToLower(), ChildItems, UseClickCmd, this.iconCls) + "}";
            }                                        

			return Item;
		}

		/// <summary>
		/// Renders all children into Ext.Node format.
		/// Use this function to Render the Root node into 1st-level menu items for TreePanel.
		/// </summary>
		/// <param name="ChildLevel">Level (1+) that children sit in tree hierarchy.</param>
		/// <returns>Formatted Ext.Node string.</returns>
		public string RenderChildren(int ChildLevel)
		{
			string ChildItems = "";
			if (this.Children != null && this.Children.Count > 0)
			{
				this.IsParent = true;
				this.ClickCommand = null;
				int ChildIndex = 1;
				this.Children.ForEach(c => ChildItems += c.Render(ChildLevel, ChildIndex++) + ",");
				if (!string.IsNullOrEmpty(ChildItems))
				{
					ChildItems = string.Format("[{0}]", ChildItems.Substring(0, ChildItems.Length - 1));
				}
			}
			return ChildItems;
		}

        /// <summary>
        /// OutPuts menu items as response. This response object is array-formatted - which is what the
        /// Ext.tree.TreePanel expects to get. It outputs all root's children as 1st-level items.
        /// </summary>
        /// <param name="RootItem">Root menu item containg all 1st-level and subsequent child items.</param>
        public static string WriteMenu(Ext.MenuItem RootItem)
        {
            return WriteMenu(RootItem, false);
        }
        /// <summary>
        /// OutPuts menu items as response. This response object is array-formatted - which is what the
        /// Ext.tree.TreePanel expects to get. Including the root item in the listing is unnecessary.
        /// </summary>
        /// <param name="RootItem">Root menu item containg all 1st-level and subsequent child items.</param>
        /// <param name="IncludeRoot">Include outputting the base root menu item as 1st-level item.</param>
        public static string WriteMenu(Ext.MenuItem RootItem, bool IncludeRoot)
        {            
            string MainItems = "";
            if (IncludeRoot)
            {
                MainItems = string.Format("[{0}]", RootItem.Render(1, 1));
            }
            else
            {
                MainItems = RootItem.RenderChildren(1);
            }
            if (!string.IsNullOrEmpty(MainItems))
            {
                return MainItems;
            }
            else
            {
                throw new Exception("Menu Exception");
            }
        }

	}
}
